/*
Copyright (c) 2025, 北京智慧物联科技有限公司.

简体中文
保留所有权利。依据GPL 2.0（以下简称"本许可"）进行许可。除非符合（遵守）本许可及以下条款，否则您不得使用此文件：

禁止任何未经授权的个人或组织以任何形式将本程序及其附属资料、创新、创意、架构设计、算法、衍生作品等用于任何商业目的、盈利活动、各类竞赛(比赛)、直播教学、录播教学、线下课程、书籍编写、教材编写、会议、培训、公益活动、项目课题、毕业设计、毕业论文、学术论文等。

本程序由版权持有人和贡献人“按原样”提供，不提供任何明示或暗示担保，包括但不局限于对适销性和特定用途适合性的暗示担保。在任何情况下，版权持有人或贡献人对因使用本程序而导致的任何直接、间接、附带、特殊、典型或后果性损害（包括但不限于购买替代商品或服务；使用损失、数据丢失或利润损失；业务中断）不承担任何责任，无论其如何产生，也不论其责任理论为何，无论是合同、严格责任还是侵权（包括疏忽或其他），即使已告知此类损害的可能性。

English
All rights reserved. Licensed under the GPL 2.0 (the "License"). You may NOT use this file except in compliance with the License and the following terms:

IT IS PROHIBITED FOR ANY UNAUTHORIZED PERSON OR ENTITY TO USE THIS PROGRAM AND ITS ANCILLARY DATA, INNOVATIONS, CONCEPTS, ARCHITECTURE DESIGN, ALGORITHMS, DERIVED WORKS, ETC., IN ANY FORM FOR COMMERCIAL PURPOSES, PROFIT-MAKING ACTIVITIES, VARIOUS COMPETITIONS (CONTESTS), LIVE TEACHING, PRE-RECORDED LESSONS, OFFLINE COURSES, BOOK WRITING, CONFERENCES, TRAININGS, PUBLIC WELFARE ACTIVITIES, PROJECTS, TOPICS, GRADUATION DESIGNS, DISSERTATIONS, THESES, AND OTHER APPLICATIONS.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h> 
#include "ohos_init.h"
#include "cmsis_os2.h"    
#include "soc_osal.h"
#include "errcode.h" 
#include "spi.h" 
#include "hal_spi.h" 
#include "include/yb_ws2812.h"  
#include "include/iot_string.h"  
#include "iot_gpio.h"  
#include "iot_gpio_ex.h" 
 
// ===== 1. 初始化

// ws63e: GPIO9 -> SPI0_OUT
#define led_gpio   9      
#define spi_port   0

int startTime, endTime;                 // 感应状态只有在指定时间段其作用，超出时间范围失效。
int grade1, grade2, grade3, grade4;     // 灯光感应等级可以从 小程序 端发起参数，即个人可以设置等级参数。分5级。

int breath_sts = 0;                     // 呼吸灯状态：0非呼吸，1在呼吸状态
int induct_sts = 0;                     // 感应状态：0非感应状态，1在感应状态
int manual_sts = 0;                     // 手动开灯：0全关，1,3,5档位 

extern int sleep_radar;                 // =1是睡眠，=0是跌倒雷达，的 uart_task.c中定义
extern int g_ConnectSuccess;            // 在 wifi_connect.c 中定义，表示wifi连接成功与否

#define ledCnt 16                        // led灯珠数量，默认8个灯珠，圆形
#define  dataLen  ledCnt*24                   // led数组 

// 开机读取nv参数，或者从Mqtt接收指令
void open_induct(void){ 
    // 从nv或mqtt传递 induct_period
    char induct_period[10] = {0};         // "22000800";  22:00~08:00
    char induct_grade[10] = {0}; 
    char pm1[33] = {0};      
    
    if(induct_period[0]==0 && induct_period[1]==0 && induct_period[2]==0 && induct_period[3]==0){
        induct_sts = 0;   
        startTime = 0; //2200;
        endTime = 800; 
    }
    else {
        char t1[2] = {0};
        strncpy(t1, induct_period, 1);
        induct_sts = atoi(t1); 
        
        char t4[5] = {0}; 
        strncpy(t4, induct_period+1, 4);
        startTime = atoi(t4);   
        strncpy(t4, induct_period+5, 4);
        endTime = atoi(t4); 
    }

    if(induct_grade[0]==0 && induct_grade[1]==0 && induct_grade[2]==0 && induct_grade[3]==0){
        grade1 = 20;
        grade2 = 40;
        grade3 = 60;
        grade4 = 80;
    }
    else {
        char t2[3] = {0};
        strncpy(t2, induct_grade, 2);
        grade1 = atoi(t2);         
        strncpy(t2, induct_grade+2, 2);
        grade2 = atoi(t2);  
        strncpy(t2, induct_grade+4, 2);
        grade3 = atoi(t2);  
        strncpy(t2, induct_grade+6, 2);
        grade4 = atoi(t2);   
    }
 
    if(induct_sts == 0) 
    { 
        ws2812_black();         // 全部关灯
    } 
    else {
        manual_sts = 0;         // 中断M
        ws2812_black();         // 全部关灯

        if(breath_sts == 1){
            stop_breath();      // 中断B，无法直接中断，需停止呼吸灯进程
        }
    }

    osal_printk("+++ person.startTime: %d, endTime: %d, grade1: %d, grade2: %d, grade3: %d, induct_sts: %d  \r\n", 
        startTime, endTime, grade1, grade2, grade3, induct_sts); 
}


// spi发送 0xfc 为ws812的 1码，发送0xe0 为ws812的 0码  
#define     on      0xfc
#define     off     0xe0

// 3byte为rgb转成24byte
void ws2812_format_new(uint8_t red, uint8_t green, uint8_t blue, char *buff) { 
    char data[24] = {0};  
    // 按位发送
    for(int i = 0; i < 8; i++)         // GREEN
    { 
        data[i] = (green & (0x01 << (7-i))) ? on : off; 
    }  

    for(int i = 0; i < 8; i++)         // RED
    { 
        data[i + 8] = ( red & (0x01 << (7-i)) ) ? on : off; 
    } 
   
    for(int i = 0; i < 8; i++)         // BLUE
    { 
        data[i + 16] = (blue & (0x01 << (7-i))) ? on : off; 
    }
     
    memcpy(buff, data, 24);
}
 

// 接线方式：灯珠的LED线(蓝色)接 hi3861的引脚A9，其他VCC(暗紫)和GND(绿色)
int ws2812_init(void){ 

    spi_attr_t  param={0};
    param.is_slave = 0; //主设备 
    param.slave_num = 1; 
 
    param.clk_phase = 0;  
    param.clk_polarity = 0; 
    param.frame_size = 0x07;    
    param.frame_format = 0;      
    param.freq_mhz = 7.2;                             // 7.2M  
    
    spi_extra_attr_t info={0}; 
 
    int ret = uapi_spi_init(spi_port, &param, &info); // SPI初始化 
    if(ret) {
        osal_printk("SpiInit fail: ret = %X \r\n", ret);
        return 0;
    } 
    
    //ret = SpiSetLoopBackMode(spi_port, 1);  //关闭回环测试
    ret = uapi_spi_set_loop_back_mode(spi_port, 1);  //关闭回环测试
    if(ret) {
        osal_printk("SpiSetLoopBackMode fail \r\n");
        return 0;
    } 
    
    //ret = SpiSetIrqMode(spi_port, 0); //不启用中断
    ret = uapi_spi_set_irq_mode(spi_port, 0, NULL, NULL); //不启用中断
    if(ret) {
        osal_printk("SpiSetIrqMode fail \r\n");
        return 0;
    }  

    //======  
    IoTGpioInit(led_gpio);  
    usleep(10000);

    // gpio9 -> spi0
    IoSetFunc(led_gpio, IOT_IO_FUNC_GPIO_9_SPI0_OUT);   
    IoTGpioSetDir(led_gpio, IOT_GPIO_DIR_OUT);   
    
    osal_printk("==> ws2812_init ok.\r\n\r\n"); 

    //ws2812_one();   // 第 2 个灯
    //osDelay(300);    
    ws2812_black(); // 黑色
    osDelay(10);

    // 默认的工作模式，自动进入感应状态，
    open_induct();  // 读取nv参数 
    
    return 1;
} 

void SpiHostWrite(uint8_t port, uint8_t *buf, uint8_t len)
{  
    //uint8_t tx_data[dataLen] = { 0 }; 
    uint8_t rx_data[dataLen] = { 0 };

    spi_xfer_data_t data = {
        .tx_buff = buf,
        .tx_bytes = len,
        .rx_buff = rx_data,
        .rx_bytes = len,
    };

    errcode_t ret;
    ret = uapi_spi_master_write(port, &data, 0);
    if(ret != ERRCODE_SUCC  ){
        osal_printk("*** SpiHostWrite: %d \r\n", ret);
    }

} 
// 关灯：全黑
void ws2812_black(void) 
{   
    char data[dataLen];    
    SpiHostWrite(spi_port, data, dataLen); 
    memset(data, 0, dataLen); 
    
    uint8_t rgb[3] = {0};
    for (int i = 0; i < ledCnt; i ++) {
        //blac	#000000	0,0,0
        rgb[0] = 0;
        rgb[1] = 0;
        rgb[2] = 0;  

        char tmp[24] = {0}; 
        ws2812_format_new(rgb[0], rgb[1], rgb[2], tmp);  // 3*8 -> 24
        for (int k = 0; k < 24; k++)
            data[i * 24 + k ] = tmp[k];
    } 
    SpiHostWrite(spi_port, data, dataLen);  
}

// 全亮：点亮全部的led灯：白色
void ws2812_five(void) 
{    
    char data[dataLen] = {0}; 
    SpiHostWrite(spi_port, data, dataLen);  
    memset(data, 0, dataLen);

    uint8_t rgb[3] = {0};
    for (int i = 0; i < ledCnt; i ++) {
        //snow1	#ffffff	255,250,250
        rgb[0] = 255;
        rgb[1] = 255;
        rgb[2] = 255;  

        char tmp[24] = {0}; 
        ws2812_format_new(rgb[0], rgb[1], rgb[2], tmp);  // 3*8 -> 24
        for (int k = 0; k < 24; k++)
            data[i * 24 + k ] = tmp[k];
    }

    SpiHostWrite(spi_port, data, dataLen); 
}

// 中档：点亮第0、2、4、6个灯：青色
void ws2812_three(void) 
{   
    char data[dataLen] = {0}; 
    SpiHostWrite(spi_port, data, dataLen); 
    memset(data, 0, dataLen);

    uint8_t rgb[3] = {0};   
    for (int i = 0; i < ledCnt; i ++) 
    {
        rgb[0] = 0;
        rgb[1] = 0;
        rgb[2] = 0; 

        if(i==0 || i==2 || i==4 || i==6)
        {
            // DarkSlateGray1	#97ffff	151,255,255，
            // 亮度降低至50%：#4C8080 76,128,128
            // 亮度降低至75%，#BFBBBB 191,187,187
            rgb[0] = 191;  
            rgb[1] = 187;  
            rgb[2] = 187;  
        } 

        char tmp[24] = {0}; 
        ws2812_format_new(rgb[0], rgb[1], rgb[2], tmp);  // 3*8 -> 24
        for (int k = 0; k < 24; k++)
            data[i * 24 + k ] = tmp[k];
    }

    SpiHostWrite(spi_port, data, dataLen); 
}
 
// 低档：点亮第0个灯：青色
void ws2812_one(void) 
{   
    char data[dataLen] = {0};
    SpiHostWrite(spi_port, data, dataLen); 
    memset(data, 0, dataLen);

    uint8_t rgb[3] = {0};    
    for (int i = 0; i < ledCnt; i ++) 
    {
        rgb[0] = 0;
        rgb[1] = 0;
        rgb[2] = 0; 

        if(i==0)
        {
            // DarkSlateGray1	#97ffff	151,255,255
            // 亮度降低至50%：#4C8080 76,128,128
            // 25%：#254040 37,64,64
            rgb[0] = 76;  
            rgb[1] = 128;  
            rgb[2] = 128;  
        } 

        char tmp[24] = {0}; 
        ws2812_format_new(rgb[0], rgb[1], rgb[2], tmp);  // 3*8 -> 24
        for (int k = 0; k < 24; k++)
            data[i * 24 + k ] = tmp[k];
    }

    SpiHostWrite(spi_port, data, dataLen); 
}


// ===== 2. 手动操控灯光档位
// 断网情况下，不能手动控制，只能是感应模式 

// 手动操控：light=0关灯，>0档级
void open_lamp(char *light)
{   
    char t1[2] = {0};
    strncpy(t1, light, 1); 
    manual_sts = atoi(t1);      // light=0关灯，>0档级
    osal_printk("*** manual_sts: %d \r\n", manual_sts);

    induct_sts = 0;             // 中断I 
    if(breath_sts == 1){
        stop_breath();          // 中断B，无法直接中断，需停止呼吸灯进程（同时修改 breath_sts=0）
    }

    if( manual_sts == 0 ) {  
        ws2812_black();         // 全黑
    }  
    if( manual_sts == 1 ){
        ws2812_one();           // 低亮  
    }
    if( manual_sts == 3 ){
        ws2812_three();         // 中亮
    }
    if( manual_sts == 5 ){
        ws2812_five();          // 高亮
    }
    
}
 

// 灯光感应效果
void induct_lamp(int move_val)
{   
    induct_sts = 1; 
    if( induct_sts==1 )
    {     
        if( move_val < grade1 )
        {  
            ws2812_black(); 
        }
        else if(move_val < grade2)
        {
            ws2812_one();
        }
        else if(move_val < grade3)
        {
            ws2812_three(); 
        }
        else 
        {
            ws2812_five();
        }
    }
}
 

#define N 15
int que_buf[N] = {0};
int que_idx = 0;  
char move_tmp[3];
int move_val = 0;

// 滤波算法
int filter(int newValue) { 
    int sum = 0;

    if(que_idx<N){
        que_buf[que_idx] = newValue;        // que_idx<N, 直接进队
        que_idx++;
    }
    else {  // que_idx=N   
        for (int i = 0; i<N-1; i++){
            que_buf[i] = que_buf[i + 1];    // 挤掉[0]，即留出[N-1]
        }
        que_buf[N-1] = newValue;            // 再进队尾
    }
 
    for(int i = 0; i < N; i++) {
        //printf("=== i: %d \r\n",  que_buf[i]);
        sum += que_buf[i];
    }
    return (int)(sum / N);
}

  